package com.app.oral.service

import com.app.oral.dao.FileDeleteFailureMapper
import com.app.oral.model.ExerciseRecord
import com.app.oral.model.ExamPaper
import com.app.oral.model.FileDeleteFailureRecord
import com.app.oral.model.FileDeleteSourceType
import com.app.oral.model.FileDeleteStatus
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.databind.ObjectMapper
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.io.IOException
import java.time.LocalDateTime

/**
 * 删除文件请求
 */
@JsonIgnoreProperties(ignoreUnknown = true)
data class DeleteFileRequest @JsonCreator constructor(
    @JsonProperty("env") val env: String,
    @JsonProperty("fileid_list") val fileIdList: List<String>
)

/**
 * 删除文件响应
 */
@JsonIgnoreProperties(ignoreUnknown = true)
data class DeleteFileResponse @JsonCreator constructor(
    @JsonProperty("errcode") val errcode: Int = -1,
    @JsonProperty("errmsg") val errmsg: String? = null,
    @JsonProperty("delete_list") val deleteList: List<DeleteResult>? = null
)

/**
 * 单个文件删除结果
 */
@JsonIgnoreProperties(ignoreUnknown = true)
data class DeleteResult @JsonCreator constructor(
    @JsonProperty("fileid") val fileId: String,
    @JsonProperty("status") val status: Int,
    @JsonProperty("errmsg") val errmsg: String? = null
)

/**
 * 文件删除操作结果
 */
data class FileDeleteResult(
    val success: Boolean,
    val message: String,
    val failedFiles: List<String> = emptyList()
)

@Service
class WeChatCloudFileDeleteService(
    private val fileDeleteFailureMapper: FileDeleteFailureMapper
) {
    
    private val logger = LoggerFactory.getLogger(WeChatCloudFileDeleteService::class.java)
    private val objectMapper = ObjectMapper()
    private val httpClient = OkHttpClient()
    
    @Value("\${wechat.cloud.env}")
    private lateinit var env: String
    
    /**
     * 删除单个文件
     */
    fun deleteFile(fileId: String): FileDeleteResult {
        return deleteFiles(listOf(fileId))
    }
    
    /**
     * 删除单个文件（带来源信息）
     */
    fun deleteFile(fileId: String, sourceType: FileDeleteSourceType, sourceId: String? = null): FileDeleteResult {
        return deleteFiles(listOf(fileId), sourceType, sourceId)
    }
    
    /**
     * 批量删除文件
     */
    fun deleteFiles(fileIds: List<String>): FileDeleteResult {
        return deleteFiles(fileIds, FileDeleteSourceType.EXERCISE_RECORD, null)
    }
    
    /**
     * 批量删除文件（带来源信息）
     */
    fun deleteFiles(fileIds: List<String>, sourceType: FileDeleteSourceType, sourceId: String? = null): FileDeleteResult {
        if (fileIds.isEmpty()) {
            return FileDeleteResult(true, "没有文件需要删除")
        }
        
        try {
            logger.info("开始删除COS文件: fileIds={}", fileIds)
            
            val url = "http://api.weixin.qq.com/tcb/batchdeletefile"
            
            val requestBody = DeleteFileRequest(
                env = env,
                fileIdList = fileIds
            )
            
            val json = objectMapper.writeValueAsString(requestBody)
            val body = json.toRequestBody("application/json".toMediaType())
            
            val request = Request.Builder()
                .url(url)
                .post(body)
                .addHeader("Content-Type", "application/json")
                .build()
            
            logger.info("请求微信API删除文件: $url, body: $json")
            
            httpClient.newCall(request).execute().use { response ->
                val responseBody = response.body?.string()
                
                logger.info("微信API删除响应状态: ${response.code}")
                logger.info("微信API删除响应内容: $responseBody")
                
                if (!response.isSuccessful) {
                    val errorMessage = "HTTP错误: ${response.code} ${response.message}"
                    recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
                    return FileDeleteResult(false, errorMessage)
                }
                
                if (responseBody.isNullOrBlank()) {
                    val errorMessage = "删除响应体为空"
                    recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
                    return FileDeleteResult(false, errorMessage)
                }
                
                return try {
                    val deleteResponse = objectMapper.readValue(responseBody, DeleteFileResponse::class.java)
                    processDeleteResponse(deleteResponse, fileIds, sourceType, sourceId)
                } catch (e: Exception) {
                    logger.error("解析删除响应失败: $responseBody", e)
                    val errorMessage = "解析删除响应失败: ${e.message}"
                    recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
                    FileDeleteResult(false, errorMessage)
                }
            }
            
        } catch (e: IOException) {
            logger.error("删除文件网络异常: fileIds={}", fileIds, e)
            val errorMessage = "网络请求失败: ${e.message}"
            recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
            return FileDeleteResult(false, errorMessage)
        } catch (e: Exception) {
            logger.error("删除文件异常: fileIds={}", fileIds, e)
            val errorMessage = "删除文件失败: ${e.message}"
            recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
            return FileDeleteResult(false, errorMessage)
        }
    }
    
    private fun processDeleteResponse(
        response: DeleteFileResponse, 
        fileIds: List<String>, 
        sourceType: FileDeleteSourceType, 
        sourceId: String?
    ): FileDeleteResult {
        if (response.errcode != 0) {
            val errorMessage = response.errmsg ?: "删除文件失败，错误码: ${response.errcode}"
            recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
            return FileDeleteResult(false, errorMessage)
        }
        
        val deleteList = response.deleteList
        if (deleteList.isNullOrEmpty()) {
            val errorMessage = "删除响应中没有文件结果"
            recordFailedFiles(fileIds, errorMessage, sourceType, sourceId)
            return FileDeleteResult(false, errorMessage)
        }
        
        val failedFiles = mutableListOf<String>()
        val successCount = deleteList.count { it.status == 0 }

        deleteList.forEach { result ->
            if (result.status != 0) {
                failedFiles.add(result.fileId)
                logger.warn("文件删除失败: fileId=${result.fileId}, status=${result.status}, error=${result.errmsg}")
            }
        }
        
        // 记录失败的文件
        if (failedFiles.isNotEmpty()) {
            recordFailedFiles(failedFiles, "部分文件删除失败", sourceType, sourceId)
        }
        
        return if (failedFiles.isEmpty()) {
            logger.info("所有文件删除成功: count=$successCount")
            FileDeleteResult(true, "删除成功，共删除${successCount}个文件")
        } else {
            logger.warn("部分文件删除失败: 成功${successCount}个, 失败${failedFiles.size}个")
            FileDeleteResult(false, "部分文件删除失败：成功${successCount}个，失败${failedFiles.size}个", failedFiles)
        }
    }
    
    /**
     * 从练习记录中提取所有音频文件ID (详细字段结构)
     */
    fun extractAudioFileIds(record: ExerciseRecord): List<String> {
        return record.extractAllAudioFileIds()
    }

    /**
     * 从试卷中提取所有文件ID (JSON结构) - 包含音频和图片
     * ⚠️ 重要修复：现在包含视听应答的音频和图片文件！
     */
    fun extractAudioFileIds(examPaper: ExamPaper): List<String> {
        return examPaper.extractAllFileIds()
    }

    /**
     * 从试卷中仅提取音频文件ID (向后兼容)
     */
    fun extractOnlyAudioFileIds(examPaper: ExamPaper): List<String> {
        return examPaper.extractAudioFileIds()
    }
    
    /**
     * 记录失败的文件删除请求
     */
    private fun recordFailedFiles(
        failedFileIds: List<String>, 
        failureReason: String, 
        sourceType: FileDeleteSourceType, 
        sourceId: String?
    ) {
        try {
            failedFileIds.forEach { fileId ->
                // 检查是否已存在相同的失败记录，避免重复记录
                if (!fileDeleteFailureMapper.existsByFileId(fileId)) {
                    val failureRecord = FileDeleteFailureRecord(
                        fileId = fileId,
                        failureReason = failureReason,
                        retryCount = 0,
                        maxRetryCount = 5,
                        status = FileDeleteStatus.PENDING,
                        sourceType = sourceType,
                        sourceId = sourceId,
                        createdTime = LocalDateTime.now(),
                        updatedTime = LocalDateTime.now()
                    )
                    fileDeleteFailureMapper.insert(failureRecord)
                    logger.info("记录文件删除失败: fileId={}, reason={}", fileId, failureReason)
                } else {
                    logger.debug("文件删除失败记录已存在，跳过: fileId={}", fileId)
                }
            }
        } catch (e: Exception) {
            logger.error("记录文件删除失败时发生异常", e)
        }
    }
    
    /**
     * 定时任务使用：重试删除失败的文件
     */
    fun retryDeleteFailedFiles(): Int {
        try {
            val failedRecords = fileDeleteFailureMapper.selectRetryableRecords()
            if (failedRecords.isEmpty()) {
                logger.info("没有需要重试删除的文件")
                return 0
            }
            
            logger.info("开始重试删除失败的文件，共{}个", failedRecords.size)
            
            val fileIds = failedRecords.map { it.fileId }
            val deleteResult = deleteFiles(fileIds, FileDeleteSourceType.EXERCISE_RECORD, "RETRY_TASK")
            
            failedRecords.forEach { record ->
                val updatedRecord = if (deleteResult.success || !deleteResult.failedFiles.contains(record.fileId)) {
                    // 删除成功，从失败记录表中移除
                    fileDeleteFailureMapper.deleteByFileId(record.fileId)
                    logger.info("文件重试删除成功: fileId={}", record.fileId)
                    null
                } else {
                    // 删除仍然失败，更新重试次数
                    val newRetryCount = record.retryCount + 1
                    val newStatus = if (newRetryCount >= record.maxRetryCount) {
                        FileDeleteStatus.FAILED
                    } else {
                        FileDeleteStatus.PENDING
                    }
                    
                    record.copy(
                        retryCount = newRetryCount,
                        status = newStatus,
                        lastRetryTime = LocalDateTime.now(),
                        updatedTime = LocalDateTime.now(),
                        failureReason = deleteResult.message
                    )
                }
                
                updatedRecord?.let { 
                    fileDeleteFailureMapper.updateById(it)
                    logger.warn("文件重试删除失败: fileId={}, retryCount={}, status={}", 
                        it.fileId, it.retryCount, it.status)
                }
            }
            
            val successCount = failedRecords.size - deleteResult.failedFiles.size
            logger.info("文件删除重试完成: 成功{}个, 失败{}个", successCount, deleteResult.failedFiles.size)
            return successCount
            
        } catch (e: Exception) {
            logger.error("重试删除失败文件时发生异常", e)
            return 0
        }
    }
}